﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Web;
using Aop.Api;
using Aop.Api.Request;
using Aop.Api.Response;
using Aop.Api.Util;
using TY.UC.Common;
using TY.UC.Common.Extension;
using TY.UT.Pay.AliPay.lib;

namespace TY.UT.Pay.AliPay
{
    /// <summary>
    /// add by 廖宇 2016.10.10
    /// 支付宝支付类
    /// </summary>
    public static class AliPayHelper
    {
        private static readonly string AppId = "ali_appid".GetStrValue();
        private static readonly string PublicKey = "ali_public_key".GetStrValue();
        private static readonly string PrivateKey = "ali_private_key".GetStrValue();
        private static readonly string NotifyUrl = "ali_notify_url".GetStrValue();
        private static readonly string RSA = "RSA2";
        private static readonly IAopClient Client = new DefaultAopClient("https://openapi.alipay.com/gateway.do", AppId, PrivateKey, "json", "1.0", "RSA2", PublicKey, "GBK");

        /// <summary>
        /// add by 廖宇 2016.10.10
        /// 支付执行
        /// </summary>
        /// <param name="dto">支付实体</param>
        /// <returns></returns>
        public static PayResult TradePay(AlipayTradePayDto dto)
        {
            AlipayTradePayRequest request = new AlipayTradePayRequest
            {
                BizContent = dto.JsonSe()
            };
            LogHelper.WriteLog("AliPay", "AliPayHelper-TradePay，调用支付宝条码支付接口请求参数：", request);
            LogHelper.WriteLog("AliPay", "AliPayHelper-TradePay，Client：", Client);
            AlipayTradePayResponse payResponse = Client.Execute(request);
            switch (payResponse.Code)
            {
                //明确返回业务失败
                case "40004":
                    LogHelper.WriteLog("AliPay", "AliPayHelper-TradePay，支付宝交易失败，payResponse.SubMsg：" +
                                       payResponse.SubMsg, dto);
                    break;

                //返回支付处理中或异常，需要进行轮询
                case "10003":
                case "20000":
                    //进行轮询
                    AlipayTradeQueryResponse queryResponse = LoopQuery(dto.out_trade_no, 20, 3000);
                    if (queryResponse == null)
                    {
                        payResponse.Code = "10003";
                        break;
                    }
                    switch (queryResponse.TradeStatus)
                    {
                        case "WAIT_BUYER_PAY":
                            payResponse.Code = "10003";
                            break;
                        case "TRADE_FINISHED":
                        case "TRADE_SUCCESS":
                            payResponse.Code = "10000";
                            break;
                        case "TRADE_CLOSED":
                            payResponse.Code = "40004";
                            break;
                    }
                    return new PayResult
                    {
                        trade_status = payResponse.Code,
                        trade_no = queryResponse.TradeNo,
                        gmt_payment = string.IsNullOrEmpty(queryResponse.SendPayDate)
                            ? DateTime.Now
                            : DateTime.Parse(queryResponse.SendPayDate)
                    };
            }
            return new PayResult
            {
                trade_status = payResponse.Code,
                trade_no = payResponse.TradeNo,
                gmt_payment = string.IsNullOrEmpty(payResponse.GmtPayment)
                    ? DateTime.Now
                    : DateTime.Parse(payResponse.GmtPayment)
            };

        }

        /// <summary>
        /// add by 廖宇 2016.10.10
        /// 轮询
        /// </summary>
        /// <param name="outTradeNo">订单号</param>
        /// <param name="count">轮询次数</param>
        /// <param name="interval">间隔时间，单位ms</param>
        /// <returns></returns>
        private static AlipayTradeQueryResponse LoopQuery(string outTradeNo, int count, int interval)
        {
            AlipayTradeQueryResponse queryResponse = null;
            for (int i = 1; i <= count; i++)
            {
                Thread.Sleep(interval);
                //执行查询
                queryResponse = TradeQuery(new { out_trade_no = outTradeNo }.JsonSe());
                //查询是否成功
                if (queryResponse == null || string.CompareOrdinal(queryResponse.Code, "10000") != 0) continue;
                //如果返回状态为交易完成、交易成功、交易关闭则返回状态，否者继续查询
                if (queryResponse.TradeStatus == "TRADE_FINISHED"
                    || queryResponse.TradeStatus == "TRADE_SUCCESS"
                    || queryResponse.TradeStatus == "TRADE_CLOSED")
                    return queryResponse;
            }
            return queryResponse;
        }

        /// <summary>
        /// add by 廖宇 2016.10.10
        /// 手机网站支付支付执行
        /// </summary>
        /// <param name="dto"></param>
        /// <param name="returnUrl"></param>
        /// <returns></returns>
        public static string PageExecute(AlipayTradeWapPayDto dto, string returnUrl)
        {
            DefaultAopClient client = new DefaultAopClient("https://openapi.alipay.com/gateway.do", AppId, PrivateKey, "json", "1.0", "RSA", PublicKey, "GBK");
            AlipayTradeWapPayRequest request = new AlipayTradeWapPayRequest
            {
                BizContent = dto.JsonSe()
            };
            request.SetNotifyUrl(NotifyUrl);
            client.return_url = returnUrl;
            LogHelper.WriteLog("AliPay", "AliPayHelper-TradePay，调用支付宝手机网站支付接口请求参数：", request);
            LogHelper.WriteLog("AliPay", "WapClient：", client);
            return client.pageExecute(request).Body;
        }

        /// <summary>
        /// add by 廖宇  2016.11.25
        /// APP支付订单签名
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        public static string AppExecute(AlipayTradeAppPayDto dto)
        {
            string timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); 
            //拼接需要签名的字符串
            string needSignString = "app_id=" + AppId + "&biz_content=" + dto.JsonSe() +
                            "&charset=utf-8&format=json&method=alipay.trade.app.pay&notify_url=" +
                            NotifyUrl + "&sign_type="+ RSA + "&timestamp=" + timestamp + "&version=1.0";
            LogHelper.WriteLog("支付宝签名原始串："+new { needSignString }.JsonSe());
            //进行签名
            var sign = AlipaySignature.RSASignCharSet(needSignString, PrivateKey, "utf-8", false, RSA);
            LogHelper.WriteLog("支付宝签名信息：" + new { needSignString, PrivateKey, PublicKey, sign }.JsonSe());
            //参数字典，用于Encode
            var dic = new Dictionary<string, string>
            {
                {"app_id", AppId},
                {"biz_content", dto.JsonSe()},
                {"charset", "utf-8"},
                {"format", "json"},
                {"method", "alipay.trade.app.pay"},
                {"notify_url",NotifyUrl},
                {"sign_type", RSA},
                {"timestamp", timestamp},
                {"version", "1.0"},
                {"sign", sign}
            };
            LogHelper.WriteLog("支付宝返回给客户端的签名信息：" + new { dic }.JsonSe());
            List<string> list = new List<string>();
            //对有所参数Encode
            foreach (var item in dic)
            {
                list.Add(item.Key + "=" + HttpUtility.UrlEncode(item.Value, Encoding.UTF8));
            }
            return string.Join("&", list);
        }

        /// <summary>
        /// add by 廖宇 2016.10.10
        /// 查询执行
        /// </summary>
        /// <param name="bizContent">支付查询json字符串</param>
        /// <returns></returns>
        private static AlipayTradeQueryResponse TradeQuery(string bizContent)
        {
            AlipayTradeQueryRequest request = new AlipayTradeQueryRequest
            {
                BizContent = bizContent
            };
            return Client.Execute(request);
        }

        /// <summary>
        /// 交易退款接口
        /// huqin 2016-10-10
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        public static PayResult TradeRefund(AlipayTradeRefundDto model)
        {
            AlipayTradeRefundRequest request = new AlipayTradeRefundRequest { BizContent = model.JsonSe() };
            AlipayTradeRefundResponse payResponse = Client.Execute(request);
            return new PayResult
            {
                trade_status = payResponse.Code,
                buyer_logon_id = payResponse.BuyerLogonId,
                buyer_id = payResponse.BuyerUserId
            };
        }
        public static string TradeQueryStatus(string out_trade_no, out decimal payamount)
        {
            payamount = 0;
            AlipayTradeQueryResponse queryResponse = TradeQuery(new { out_trade_no = out_trade_no }.JsonSe());
            LogHelper.WriteLog("TradeQueryStatus方法，查询支付订单信息：" + new { out_trade_no = out_trade_no, queryResponse = queryResponse }.JsonSe());
            switch (queryResponse.TradeStatus)
            {
                case "WAIT_BUYER_PAY"://交易创建，等待买家付款

                    break;
                case "TRADE_FINISHED":
                case "TRADE_SUCCESS":
                    decimal.TryParse(queryResponse.TotalAmount, out payamount);
                    break;
                case "TRADE_CLOSED":

                    break;
            }
            //交易状态：WAIT_BUYER_PAY（交易创建，等待买家付款）、
            //TRADE_CLOSED（未付款交易超时关闭，或支付完成后全额退款）、
            //TRADE_SUCCESS（交易支付成功）、
            //TRADE_FINISHED（交易结束，不可退款）
            return queryResponse.TradeStatus;
        }
        /// <summary>
        /// 收银员通过收银台或商户后台调用支付宝接口，生成二维码后，展示给用户，由用户扫描二维码完成订单支付。
        /// </summary>
        /// <param name="out_trade_no">商户订单号</param>
        /// <param name="total_amount">订单总金额</param>
        /// <param name="subject">订单标题</param>
        /// <param name="body">对交易或商品的描述</param>
        /// <returns>支付二维码</returns>
        public static string AcquirePrecreate(string out_trade_no,string total_amount,string subject,string body="")
        {
            AlipayTradePrecreateRequest request = new AlipayTradePrecreateRequest()
            {
                 BizContent = new { out_trade_no= out_trade_no, total_amount=float.Parse(total_amount), timeout_express = "90m",subject = subject }.JsonSe()
            };//创建API对应的request类
            request.SetNotifyUrl(NotifyUrl);
            LogHelper.WriteLog("AliPay", "AliPayHelper-AcquirePrecreate，调用支付宝扫码支付接口请求参数：", request);
            LogHelper.WriteLog("AliPay", "AliPayHelper-AcquirePrecreate，Client：", Client);
            AlipayTradePrecreateResponse payResponse = Client.Execute(request);
            LogHelper.WriteLog("AliPay", "AliPayHelper-AcquirePrecreate，调用支付宝扫码支付接口返回参数：", payResponse);
            if (payResponse.Code=="10000")
            {//Success
                return payResponse.QrCode;
            }
            return null;
        }

    }
}
